<style lang="less">
  .frame {
    z-index: 2;
		background: rgba(0, 0, 0, 1);
    .frame-list {
      height: 172rpx;
      white-space: nowrap;
      .frame-item {
        margin: 26rpx 12rpx 0;
        width: auto;
        height: 120rpx;
        box-sizing: border-box;
        &:first-child {
          margin-left: 30rpx;
        }
        &:last-child {
          margin-right: 30rpx;
        }
      }
      .frame-item--active {
        outline: var(--theme) solid 2rpx;
      }
    }
    .frame-view {
      overflow: hidden;
      width: 750rpx;
      height: 750rpx;
      background: #fff;
      .bg-warp {
        width: auto;
        height: auto;
        pointer-events: auto;
      }
      .bg-image {
      }
      .frame-bg {
        position: absolute;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        background: url(https://fujifilm-c2b.oss-cn-beijing.aliyuncs.com/BASIC/voucher5ed71fa4247f8.jpg) no-repeat;
        background-size: 100% 100%;
        pointer-events: none;
      }
    }
    .canvas {
      position: absolute;
      top: -999px;
      left: -999px;
      z-index: -1;
      width: 750rpx;
      height: 750rpx;
    }
  }
</style>

<template>
  <view class="frame fixed-view flex flex-col">
    <!-- 画布 -->
    <view class="flex-1 flex align-center">
      <movable-area class="frame-view">
        <movable-view id="bg-warp" class="bg-warp" direction="all" :x="x" :y="y" :animation="false" scale @scale="onScale"
          :style="{ width: movableImageSize.width + 'px', height: movableImageSize.height + 'px' }" @touchmove="touchmove" @touchstart="touchstart">
          <image class="bg-image" :style="{ width: imageStyle.width, height: imageStyle.height, transform: `rotate(${deg}deg)` }" :src="localUrl" :mode="mode === 'widthFix' ? 'heightFix' : 'widthFix'" @load="movableImageLoad" />
        </movable-view>
        <view class="frame-bg"></view>
      </movable-area>
    </view>
    <canvas type="2d" class="canvas" id="canvas"></canvas>
    <!-- 底部操作栏 -->
    <handle-bar title="相框" @close="backEdit" @submit="submit">
      <scroll-view class="frame-list" scroll-x>
        <image v-for="(item, index) in 10" :key="item" class="frame-item" :class="index === frameIndex ? 'frame-item--active' : ''" src="https://fujifilm-c2b.oss-cn-beijing.aliyuncs.com/BASIC/voucher5ed71fa4247f8.jpg" mode="heightFix" @click="selectFrame(index)" />
      </scroll-view>
    </handle-bar>
  </view>
</template>

<script>
import { createNamespacedHelpers } from 'vuex'
import systemMixin from '@/mixin/system'
import { funcSync, debounce, rpxTopx, nextTick } from '@/utils/index'
import HandleBar from '@/biz-components/handle-bar'
const { mapState, mapMutations } = createNamespacedHelpers('app')
/**
 * 加相框
 */
export default {
  name: 'Frame',
	mixins: [systemMixin],
  components: {
    HandleBar
  },
  data() {
    return {
      frameIndex: 0,  // 选中相框
      movableImageSize: {
        width: 375,
        height: 375
      },  // 移动图片大小
      frameUrl: 'https://fujifilm-c2b.oss-cn-beijing.aliyuncs.com/BASIC/voucher5ed71fa4247f8.jpg',
      scaleValue: 1,  // 水印缩放倍数
      x: 0, // 初始图片x坐标
      y: 0, // 初始图片y坐标
      pageX: 0, // 相对页面x坐标
      pageY: 0, // 相对页面y坐标
      deg: 0, // 当前旋转角度
      lastDeg: 0,  // 上一次旋转角度
      nextDeg: 0, // 下一次旋转角度
      mode: 'widthFix', // 图片模式
      offsetX: 0,
      offsetY: 0,
    }
  },
  computed: {
		...mapState(['localUrl']),
    // 图样式
		imageStyle(state) {
			if (this.mode === 'heightFix') {
				return { width: '750rpx', height: 'auto' }
			}
			return { width: 'auto', height: '750rpx' }
		},
  },
  methods: {
    ...mapMutations(['setLocalUrl', 'setOriginUrl']),
    // 获取移动图片
    getMovableImage() {
      return new Promise((resolve, reject) => {
				try {
          uni.createSelectorQuery()
            .in(this)
						.select('.bg-image')
            .boundingClientRect()
						.selectViewport()
						.scrollOffset()
						.exec(res => {
							resolve(res[0])
						})
				} catch(err) {
					reject(err)
				}
			})
    },
    // 移动图片加载
    async movableImageLoad() {
      // 获取图片初始宽高
      const { width, height } = await this.getMovableImage()
      const warpWidth = rpxTopx(750)
      const warpHeight = rpxTopx(750)
      // 计算图片模式
      const frameRatio = warpWidth / warpHeight // 相框宽高比
			const imgRatio = width / height // 图片宽高比
      this.mode = frameRatio > imgRatio ? 'heightFix' : 'widthFix'
      await nextTick(this)
      // 获取图片真实宽高
      const { width: imageWidth, height: heightWidth, left, top } = await this.getMovableImage()
      this.movableImageSize = { width: imageWidth, height: heightWidth }
      // 图片居中
      this.x = (warpWidth - imageWidth) / 2
      this.y = (warpHeight - heightWidth) / 2
      this.offsetX = Math.abs(this.x)
      this.offsetY = Math.abs(this.y)
      this.pageX = left
      this.pageY = top
      // 初始化画布
      this.initCanvas()
    },
    // 初始化画布
		async initCanvas() {
      const { width, height, node } = await this.getCanvas()	// canvas高宽、实例
			const ctx = node.getContext('2d')	// canvas上下文
			const { pixelRatio } = uni.getSystemInfoSync()	// 终端屏幕比例
			// 根据比例修正canvas高宽和比例
			node.width = width * pixelRatio
			node.height = height * pixelRatio
      ctx.scale(pixelRatio, pixelRatio)
    },
    // 获取画布
		getCanvas() {
			return new Promise((resolve, reject) => {
				try {
          uni.createSelectorQuery()
            .in(this)
						.select('.canvas')
						.fields({ node: true, size: true })
						.exec(res => {
							resolve(res[0])
						})
				} catch(err) {
					reject(err)
				}
			})
    },
    // 加载图片
		loadImage(img) {
			return new Promise((resolve, reject) => {
				try {
					img.onload = () => {
						resolve()
					}
					img.onerror = (e) => {
						uni.showToast({ icon: 'none',	title: '保存失败!' })
						console.error('图片加载失败')
						reject({ error: '图片加载失败' })
					}
				} catch(err) {
					reject(err)
				}
			})
		},
    // 缩放水印
    onScale: debounce(function(e) {
      this.scaleValue = e.detail.scale
    }, 250),
    // 选择相框
    selectFrame(index) {
      this.frameIndex = index
    },
    // 返回编辑页
    backEdit() {
      this.$emit('close')
    },
    // 编辑完成
    async submit() {
      uni.showLoading({	title: '保存中' })
      // 获取图片坐标
      const { left, top, width: imageWidth, height: imageHieght } = await this.getMovableImage()
      const { width, height, node } = await this.getCanvas()	// canvas高宽、实例
      const ctx = node.getContext('2d')	// canvas上下文
      // 清空画布
      ctx.clearRect(0, 0, width, height)
      // 填充白色背景
      ctx.fillStyle = '#ffffff'
      ctx.fillRect(0, 0, width, height)
      // 加图片
			const coverImage = node.createImage()
      coverImage.src = this.localUrl
      // 等待图片加载完毕
      await this.loadImage(coverImage)
      // 图片旋转
      const imageX = left - this.pageX
      const imageY = top - this.pageY
      const ox = imageX + imageWidth / 2
      const oy = imageY + imageHieght / 2
      ctx.translate(ox, oy)
      // ctx.rotate(Math.PI / 180 * this.deg)
      ctx.drawImage(coverImage, -ox + imageX, -oy + imageY, this.movableImageSize.width * this.scaleValue, this.movableImageSize.height * this.scaleValue)
      // ctx.rotate(Math.PI / 180 * -this.deg)
      ctx.translate(-ox, -oy)
      const frameImage = node.createImage()
      frameImage.src = this.frameUrl
      await this.loadImage(frameImage)
      ctx.drawImage(frameImage, 0, 0, width, height)
      const { tempFilePath } = await funcSync(uni.canvasToTempFilePath, { canvas: node, quality: 1 }, uni.hideLoading)
      this.setLocalUrl(tempFilePath)
      this.setOriginUrl(tempFilePath)
      uni.hideLoading()	// 结束加载动画
      this.$emit('submit')
    },
    touchmove(e) {
      // 过滤单指
      if (e.touches.length < 2) {
        return
      }
      // this.deg = (this.lastDeg + this.nextDeg - this.getDeg(e)) % 360
    },
    touchstart(e) {
      // 过滤单指
      if (e.touches.length < 2) {
        return
      }
      this.lastDeg = this.deg
      this.nextDeg = this.getDeg(e)
      e.preventDefault()
    },
    // 获取角度
    getDeg(e) {
      const x1 = e.touches[0].pageX
      const y1 = e.touches[0].pageY
      const x2 = e.touches[1].pageX
      const y2 = e.touches[1].pageY
      const x = x2 - x1
      const y = y1 - y2
      return Math.atan2(y, x) * 180 / Math.PI
    }
  }
}
</script>